1 /*
  2  *  Copyright (c) 2020, 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.  Oracle designates this
  8  *  particular file as subject to the "Classpath" exception as provided
  9  *  by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  *  This code is distributed in the hope that it will be useful, but WITHOUT
 12  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  *  version 2 for more details (a copy is included in the LICENSE file that
 15  *  accompanied this code).
 16  *
 17  *  You should have received a copy of the GNU General Public License version
 18  *  2 along with this work; if not, write to the Free Software Foundation,
 19  *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  *   Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  *  or visit www.oracle.com if you need additional information or have any
 23  *  questions.
 24  *
 25  */
 26 
 27 package jdk.internal.clang;
 28 
 29 import jdk.incubator.foreign.MemoryAddress;
 30 import jdk.incubator.foreign.MemorySegment;
 31 import jdk.incubator.foreign.NativeSymbol;
 32 import jdk.incubator.foreign.ResourceScope;
 33 import jdk.incubator.foreign.SegmentAllocator;
 34 import jdk.internal.clang.libclang.CXCursorVisitor;
 35 import jdk.internal.clang.libclang.Index_h;
 36 
 37 import java.util.ArrayList;
 38 import java.util.stream.Stream;
 39 
 40 import static jdk.internal.clang.LibClang.IMPLICIT_ALLOCATOR;
 41 
 42 public final class Cursor {
 43 
 44     private final MemorySegment cursor;
 45     private final int kind;
 46 
 47     Cursor(MemorySegment cursor) {
 48         this.cursor = cursor;
 49         kind = Index_h.clang_getCursorKind(cursor);
 50     }
 51 
 52     public boolean isDeclaration() {
 53         return Index_h.clang_isDeclaration(kind) != 0;
 54     }
 55 
 56     public boolean isPreprocessing() {
 57         return Index_h.clang_isPreprocessing(kind) != 0;
 58     }
 59 
 60     public boolean isInvalid() {
 61         return Index_h.clang_isInvalid(kind) != 0;
 62     }
 63 
 64     public boolean isDefinition() {
 65         return Index_h.clang_isCursorDefinition(cursor) != 0;
 66     }
 67 
 68     public boolean isAttribute() { return Index_h.clang_isAttribute(kind) != 0; }
 69 
 70     public boolean isAnonymousStruct() {
 71         return Index_h.clang_Cursor_isAnonymousRecordDecl(cursor) != 0;
 72     }
 73 
 74     public boolean isMacroFunctionLike() {
 75         return Index_h.clang_Cursor_isMacroFunctionLike(cursor) != 0;
 76     }
 77 
 78     public String spelling() {
 79         return LibClang.CXStrToString(allocator ->
 80             Index_h.clang_getCursorSpelling(allocator, cursor));
 81     }
 82 
 83     public String USR() {
 84         return LibClang.CXStrToString(allocator ->
 85                 Index_h.clang_getCursorUSR(allocator, cursor));
 86     }
 87 
 88     public String prettyPrinted(PrintingPolicy policy) {
 89         return LibClang.CXStrToString(allocator ->
 90             Index_h.clang_getCursorPrettyPrinted(allocator, cursor, policy.ptr()));
 91     }
 92 
 93     public String prettyPrinted() {
 94         try (PrintingPolicy policy = getPrintingPolicy()) {
 95             return prettyPrinted(policy);
 96         }
 97     }
 98 
 99     public String displayName() {
100         return LibClang.CXStrToString(allocator ->
101                 Index_h.clang_getCursorDisplayName(allocator, cursor));
102     }
103 
104     public boolean equalCursor(Cursor other) {
105         return Index_h.clang_equalCursors(cursor, other.cursor) != 0;
106     }
107 
108     public Type type() {
109         return new Type(Index_h.clang_getCursorType(IMPLICIT_ALLOCATOR, cursor));
110     }
111 
112     public Type getEnumDeclIntegerType() {
113         return new Type(Index_h.clang_getEnumDeclIntegerType(IMPLICIT_ALLOCATOR, cursor));
114     }
115 
116     public Cursor getDefinition() {
117         return new Cursor(Index_h.clang_getCursorDefinition(IMPLICIT_ALLOCATOR, cursor));
118     }
119 
120     public SourceLocation getSourceLocation() {
121         MemorySegment loc = Index_h.clang_getCursorLocation(IMPLICIT_ALLOCATOR, cursor);
122         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
123             if (Index_h.clang_equalLocations(loc, Index_h.clang_getNullLocation(
124                     SegmentAllocator.nativeAllocator(scope))) != 0) {
125                 return null;
126             }
127         }
128         return new SourceLocation(loc);
129     }
130 
131     public SourceRange getExtent() {
132         MemorySegment range = Index_h.clang_getCursorExtent(IMPLICIT_ALLOCATOR, cursor);
133         if (Index_h.clang_Range_isNull(range) != 0) {
134             return null;
135         }
136         return new SourceRange(range);
137     }
138 
139     public int numberOfArgs() {
140         return Index_h.clang_Cursor_getNumArguments(cursor);
141     }
142 
143     public Cursor getArgument(int idx) {
144         return new Cursor(Index_h.clang_Cursor_getArgument(IMPLICIT_ALLOCATOR, cursor, idx));
145     }
146 
147     // C long long, 64-bit
148     public long getEnumConstantValue() {
149         return Index_h.clang_getEnumConstantDeclValue(cursor);
150     }
151 
152     // C unsigned long long, 64-bit
153     public long getEnumConstantUnsignedValue() {
154         return Index_h.clang_getEnumConstantDeclUnsignedValue(cursor);
155     }
156 
157     public boolean isBitField() {
158         return Index_h.clang_Cursor_isBitField(cursor) != 0;
159     }
160 
161     public int getBitFieldWidth() {
162         return Index_h.clang_getFieldDeclBitWidth(cursor);
163     }
164 
165     public CursorKind kind() {
166         return CursorKind.valueOf(kind);
167     }
168 
169     public CursorLanguage language() {
170         return CursorLanguage.valueOf(Index_h.clang_getCursorLanguage(cursor));
171     }
172 
173     public int kind0() {
174         return kind;
175     }
176 
177     /**
178      * For a cursor that is a reference, retrieve a cursor representing the entity that it references.
179      */
180     public Cursor getCursorReferenced() {
181         return new Cursor(Index_h.clang_getCursorReferenced(
182                 IMPLICIT_ALLOCATOR, cursor));
183     }
184 
185     private static class CursorChildren {
186         private static final ArrayList<Cursor> children = new ArrayList<>();
187         private static final NativeSymbol callback = CXCursorVisitor.allocate((c, p, d) -> {
188             MemorySegment copy = MemorySegment.allocateNative(c.byteSize(), ResourceScope.newImplicitScope());
189             copy.copyFrom(c);
190             Cursor cursor = new Cursor(copy);
191             children.add(cursor);
192             return Index_h.CXChildVisit_Continue();
193         }, ResourceScope.newImplicitScope());
194 
195         synchronized static Stream<Cursor> get(Cursor c) {
196             try {
197                 Index_h.clang_visitChildren(c.cursor, callback, MemoryAddress.NULL);
198                 return new ArrayList<>(children).stream();
199             } finally {
200                 children.clear();
201             }
202         }
203     }
204 
205     public Stream<Cursor> children() {
206         return CursorChildren.get(this);
207     }
208 
209     public Stream<Cursor> allChildren() {
210         return children().flatMap(c -> Stream.concat(Stream.of(c), c.children()));
211     }
212 
213     public String getMangling() {
214         return LibClang.CXStrToString(allocator ->
215                 Index_h.clang_Cursor_getMangling(allocator, cursor));
216     }
217 
218     public TranslationUnit getTranslationUnit() {
219         return new TranslationUnit(Index_h.clang_Cursor_getTranslationUnit(cursor));
220     }
221 
222     private MemoryAddress eval0() {
223         return Index_h.clang_Cursor_Evaluate(cursor);
224     }
225 
226     public EvalResult eval() {
227         MemoryAddress ptr = eval0();
228         return ptr == MemoryAddress.NULL ? EvalResult.erroneous : new EvalResult(ptr);
229     }
230 
231     public PrintingPolicy getPrintingPolicy() {
232         return new PrintingPolicy(Index_h.clang_getCursorPrintingPolicy(cursor));
233     }
234 
235     @Override
236     public boolean equals(Object other) {
237         if (this == other) {
238             return true;
239         }
240         if (!(other instanceof Cursor)) {
241             return false;
242         }
243         return (Index_h.clang_equalCursors(cursor, ((Cursor)other).cursor) != 0);
244     }
245 
246     @Override
247     public int hashCode() {
248         return spelling().hashCode();
249     }
250 }