1 /*
   2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package jdk.internal.clang;
  25 
  26 import clang.*;
  27 import clang.Index;
  28 
  29 import static clang.Index.CXCursor;
  30 import static clang.Index.CXSourceLocation;
  31 import static clang.Index.CXSourceRange;
  32 
  33 import java.foreign.memory.Pointer;
  34 import java.foreign.Scope;
  35 import java.util.ArrayList;
  36 import java.util.stream.Stream;
  37 
  38 public class Cursor {
  39 
  40     private final CXCursor cursor;
  41     private final int kind;
  42 
  43     Cursor(CXCursor cursor) {
  44         this.cursor = cursor;
  45         kind = LibClang.lib.clang_getCursorKind(cursor);
  46     }
  47     public boolean isDeclaration() {
  48         return LibClang.lib.clang_isDeclaration(kind) != 0;
  49     }
  50 
  51     public boolean isPreprocessing() { return LibClang.lib.clang_isPreprocessing(kind) != 0; }
  52 
  53     public boolean isInvalid() {
  54         return LibClang.lib.clang_isInvalid(kind) != 0;
  55     }
  56 
  57     public boolean isDefinition() {
  58         return LibClang.lib.clang_isCursorDefinition(cursor) != 0;
  59     }
  60 
  61     public boolean isAnonymousStruct() { return LibClang.lib.clang_Cursor_isAnonymous(cursor) != 0; }
  62 
  63     public boolean isMacroFunctionLike() {
  64         return LibClang.lib.clang_Cursor_isMacroFunctionLike(cursor) != 0;
  65     }
  66 
  67     public String spelling() {
  68         return LibClang.CXStrToString(
  69                 LibClang.lib.clang_getCursorSpelling(cursor));
  70     }
  71 
  72     public String USR() {
  73         return LibClang.CXStrToString(
  74                 LibClang.lib.clang_getCursorUSR(cursor));
  75     }
  76 
  77     public boolean equalCursor(Cursor other) {
  78         return LibClang.lib.clang_equalCursors(cursor, other.cursor) != 0;
  79     }
  80 
  81     public Type type() {
  82         return new Type(LibClang.lib.clang_getCursorType(cursor));
  83     }
  84 
  85     public Type getEnumDeclIntegerType() {
  86         return new Type(LibClang.lib.clang_getEnumDeclIntegerType(cursor));
  87     }
  88 
  89     public Cursor getDefinition() {
  90         return new Cursor(LibClang.lib.clang_getCursorDefinition(cursor));
  91     }
  92 
  93     public SourceLocation getSourceLocation() {
  94         CXSourceLocation loc = LibClang.lib.clang_getCursorLocation(cursor);
  95         if (LibClang.lib.clang_equalLocations(loc, LibClang.lib.clang_getNullLocation()) != 0) {
  96             return null;
  97         }
  98         return new SourceLocation(loc);
  99     }
 100 
 101     public SourceRange getExtent() {
 102         CXSourceRange range = LibClang.lib.clang_getCursorExtent(cursor);
 103         if (LibClang.lib.clang_Range_isNull(range) != 0) {
 104             return null;
 105         }
 106         return new SourceRange(range);
 107     }
 108 
 109     public int numberOfArgs() {
 110         return LibClang.lib.clang_Cursor_getNumArguments(cursor);
 111     }
 112 
 113     public Cursor getArgument(int idx) {
 114         return new Cursor(LibClang.lib.clang_Cursor_getArgument(cursor, idx));
 115     }
 116 
 117     // C long long, 64-bit
 118     public long getEnumConstantValue() {
 119         return LibClang.lib.clang_getEnumConstantDeclValue(cursor);
 120     }
 121 
 122     // C unsigned long long, 64-bit
 123     public long getEnumConstantUnsignedValue() {
 124         return LibClang.lib.clang_getEnumConstantDeclUnsignedValue(cursor);
 125     }
 126 
 127     public boolean isBitField() {
 128         return LibClang.lib.clang_Cursor_isBitField(cursor) != 0;
 129     }
 130 
 131     public int getBitFieldWidth() {
 132         return LibClang.lib.clang_getFieldDeclBitWidth(cursor);
 133     }
 134 
 135     public CursorKind kind() {
 136         return CursorKind.valueOf(kind);
 137     }
 138 
 139     public Stream<Cursor> children() {
 140         final ArrayList<Cursor> ar = new ArrayList<>();
 141         // FIXME: need a way to pass ar down as user data d
 142         try (Scope sc = Scope.globalScope().fork()) {
 143             LibClang.lib.clang_visitChildren(cursor, sc.allocateCallback((c, p, d) -> {
 144                 ar.add(new Cursor(c));
 145                 return LibClang.lib.CXChildVisit_Continue();
 146             }), Pointer.ofNull());
 147             return ar.stream();
 148         }
 149     }
 150 
 151     public Stream<Cursor> allChildren() {
 152         return children().flatMap(c -> Stream.concat(Stream.of(c), c.children()));
 153     }
 154 
 155     public String getMangling() {
 156         return LibClang.CXStrToString(
 157                 LibClang.lib.clang_Cursor_getMangling(cursor));
 158     }
 159 
 160     public TranslationUnit getTranslationUnit() {
 161         return new TranslationUnit(LibClang.lib.clang_Cursor_getTranslationUnit(cursor));
 162     }
 163 
 164     public EvalResult eval() {
 165         //this throws because, for now, the eval API is never needed when parsing Index.h
 166         //which only contains simple numeric macros which can be parsed w/o libclang support.
 167         throw new UnsupportedOperationException("Eval API missing!");
 168     }
 169 
 170     @Override
 171     public boolean equals(Object other) {
 172         if (this == other) {
 173             return true;
 174         }
 175         if (!(other instanceof Cursor)) {
 176             return false;
 177         }
 178         return (LibClang.lib.clang_equalCursors(cursor, ((Cursor)other).cursor) != 0);
 179     }
 180 
 181     @Override
 182     public int hashCode() {
 183         return spelling().hashCode();
 184     }
 185 }