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.util.ArrayList;
  35 import java.util.stream.Stream;
  36 
  37 public class Cursor {
  38 
  39     private final CXCursor cursor;
  40     private final int kind;
  41 
  42     Cursor(CXCursor cursor) {
  43         this.cursor = cursor;
  44         kind = LibClang.lib.clang_getCursorKind(cursor);
  45     }
  46     public boolean isDeclaration() {
  47         return LibClang.lib.clang_isDeclaration(kind) != 0;
  48     }
  49 
  50     public boolean isPreprocessing() { return LibClang.lib.clang_isPreprocessing(kind) != 0; }
  51 
  52     public boolean isInvalid() {
  53         return LibClang.lib.clang_isInvalid(kind) != 0;
  54     }
  55 
  56     public boolean isDefinition() {
  57         return LibClang.lib.clang_isCursorDefinition(cursor) != 0;
  58     }
  59 
  60     public boolean isAnonymousStruct() { return LibClang.lib.clang_Cursor_isAnonymous(cursor) != 0; }
  61 
  62     public boolean isAnonymousEnum() {
  63         // libclang::clang_Cursor_isAnonymous only applies to struct, not enum
  64         return (type().kind() == TypeKind.Enum && spelling().isEmpty());
  65     }
  66 
  67     public boolean isAnonymous() {
  68         return isAnonymousStruct() || isAnonymousEnum();
  69     }
  70 
  71     public boolean isMacroFunctionLike() {
  72         return LibClang.lib.clang_Cursor_isMacroFunctionLike(cursor) != 0;
  73     }
  74 
  75     public String spelling() {
  76         return LibClang.CXStrToString(
  77                 LibClang.lib.clang_getCursorSpelling(cursor));
  78     }
  79 
  80     public String USR() {
  81         return LibClang.CXStrToString(
  82                 LibClang.lib.clang_getCursorUSR(cursor));
  83     }
  84 
  85     public boolean equalCursor(Cursor other) {
  86         return LibClang.lib.clang_equalCursors(cursor, other.cursor) != 0;
  87     }
  88 
  89     public Type type() {
  90         return new Type(LibClang.lib.clang_getCursorType(cursor));
  91     }
  92 
  93     public Type getEnumDeclIntegerType() {
  94         return new Type(LibClang.lib.clang_getEnumDeclIntegerType(cursor));
  95     }
  96 
  97     public Cursor getDefinition() {
  98         return new Cursor(LibClang.lib.clang_getCursorDefinition(cursor));
  99     }
 100 
 101     public SourceLocation getSourceLocation() {
 102         CXSourceLocation loc = LibClang.lib.clang_getCursorLocation(cursor);
 103         if (LibClang.lib.clang_equalLocations(loc, LibClang.lib.clang_getNullLocation()) != 0) {
 104             return null;
 105         }
 106         return new SourceLocation(loc);
 107     }
 108 
 109     public SourceRange getExtent() {
 110         CXSourceRange range = LibClang.lib.clang_getCursorExtent(cursor);
 111         if (LibClang.lib.clang_Range_isNull(range) != 0) {
 112             return null;
 113         }
 114         return new SourceRange(range);
 115     }
 116 
 117     public int numberOfArgs() {
 118         return LibClang.lib.clang_Cursor_getNumArguments(cursor);
 119     }
 120 
 121     public Cursor getArgument(int idx) {
 122         return new Cursor(LibClang.lib.clang_Cursor_getArgument(cursor, idx));
 123     }
 124 
 125     // C long long, 64-bit
 126     public long getEnumConstantValue() {
 127         return LibClang.lib.clang_getEnumConstantDeclValue(cursor);
 128     }
 129 
 130     // C unsigned long long, 64-bit
 131     public long getEnumConstantUnsignedValue() {
 132         return LibClang.lib.clang_getEnumConstantDeclUnsignedValue(cursor);
 133     }
 134 
 135     public boolean isBitField() {
 136         return LibClang.lib.clang_Cursor_isBitField(cursor) != 0;
 137     }
 138 
 139     public int getBitFieldWidth() {
 140         return LibClang.lib.clang_getFieldDeclBitWidth(cursor);
 141     }
 142 
 143     public CursorKind kind() {
 144         return CursorKind.valueOf(kind);
 145     }
 146 
 147     public boolean equals(Cursor other) {
 148         return (LibClang.lib.clang_equalCursors(cursor, other.cursor) != 0);
 149     }
 150 
 151     public Stream<Cursor> children() {
 152         final ArrayList<Cursor> ar = new ArrayList<>();
 153         // FIXME: need a way to pass ar down as user data d
 154         LibClang.lib.clang_visitChildren(cursor, (c, p, d) -> {
 155             ar.add(new Cursor(c));
 156             return Index.CXChildVisit_Continue;
 157         }, Pointer.nullPointer());
 158         return ar.stream();
 159     }
 160 
 161     public Stream<Cursor> stream() {
 162         return children().flatMap(c -> Stream.concat(Stream.of(c), c.children()));
 163     }
 164 
 165     public String getMangling() {
 166         return LibClang.CXStrToString(
 167                 LibClang.lib.clang_Cursor_getMangling(cursor));
 168     }
 169 
 170     public TranslationUnit getTranslationUnit() {
 171         return new TranslationUnit(LibClang.lib.clang_Cursor_getTranslationUnit(cursor));
 172     }
 173 }