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 isMacroFunctionLike() {
  63         return LibClang.lib.clang_Cursor_isMacroFunctionLike(cursor) != 0;
  64     }
  65 
  66     public String spelling() {
  67         return LibClang.CXStrToString(
  68                 LibClang.lib.clang_getCursorSpelling(cursor));
  69     }
  70 
  71     public String USR() {
  72         return LibClang.CXStrToString(
  73                 LibClang.lib.clang_getCursorUSR(cursor));
  74     }
  75 
  76     public boolean equalCursor(Cursor other) {
  77         return LibClang.lib.clang_equalCursors(cursor, other.cursor) != 0;
  78     }
  79 
  80     public Type type() {
  81         return new Type(LibClang.lib.clang_getCursorType(cursor));
  82     }
  83 
  84     public Type getEnumDeclIntegerType() {
  85         return new Type(LibClang.lib.clang_getEnumDeclIntegerType(cursor));
  86     }
  87 
  88     public Cursor getDefinition() {
  89         return new Cursor(LibClang.lib.clang_getCursorDefinition(cursor));
  90     }
  91 
  92     public SourceLocation getSourceLocation() {
  93         CXSourceLocation loc = LibClang.lib.clang_getCursorLocation(cursor);
  94         if (LibClang.lib.clang_equalLocations(loc, LibClang.lib.clang_getNullLocation()) != 0) {
  95             return null;
  96         }
  97         return new SourceLocation(loc);
  98     }
  99 
 100     public SourceRange getExtent() {
 101         CXSourceRange range = LibClang.lib.clang_getCursorExtent(cursor);
 102         if (LibClang.lib.clang_Range_isNull(range) != 0) {
 103             return null;
 104         }
 105         return new SourceRange(range);
 106     }
 107 
 108     public int numberOfArgs() {
 109         return LibClang.lib.clang_Cursor_getNumArguments(cursor);
 110     }
 111 
 112     public Cursor getArgument(int idx) {
 113         return new Cursor(LibClang.lib.clang_Cursor_getArgument(cursor, idx));
 114     }
 115 
 116     // C long long, 64-bit
 117     public long getEnumConstantValue() {
 118         return LibClang.lib.clang_getEnumConstantDeclValue(cursor);
 119     }
 120 
 121     // C unsigned long long, 64-bit
 122     public long getEnumConstantUnsignedValue() {
 123         return LibClang.lib.clang_getEnumConstantDeclUnsignedValue(cursor);
 124     }
 125 
 126     public boolean isBitField() {
 127         return LibClang.lib.clang_Cursor_isBitField(cursor) != 0;
 128     }
 129 
 130     public int getBitFieldWidth() {
 131         return LibClang.lib.clang_getFieldDeclBitWidth(cursor);
 132     }
 133 
 134     public CursorKind kind() {
 135         return CursorKind.valueOf(kind);
 136     }
 137 
 138     public Stream<Cursor> children() {
 139         final ArrayList<Cursor> ar = new ArrayList<>();
 140         // FIXME: need a way to pass ar down as user data d
 141         LibClang.lib.clang_visitChildren(cursor, (c, p, d) -> {
 142             ar.add(new Cursor(c));
 143             return Index.CXChildVisit_Continue;
 144         }, Pointer.nullPointer());
 145         return ar.stream();
 146     }
 147 
 148     public Stream<Cursor> allChildren() {
 149         return children().flatMap(c -> Stream.concat(Stream.of(c), c.children()));
 150     }
 151 
 152     public String getMangling() {
 153         return LibClang.CXStrToString(
 154                 LibClang.lib.clang_Cursor_getMangling(cursor));
 155     }
 156 
 157     public TranslationUnit getTranslationUnit() {
 158         return new TranslationUnit(LibClang.lib.clang_Cursor_getTranslationUnit(cursor));
 159     }
 160 
 161     @Override
 162     public boolean equals(Object other) {
 163         if (this == other) {
 164             return true;
 165         }
 166         if (!(other instanceof Cursor)) {
 167             return false;
 168         }
 169         return (LibClang.lib.clang_equalCursors(cursor, ((Cursor)other).cursor) != 0);
 170     }
 171 
 172     @Override
 173     public int hashCode() {
 174         return spelling().hashCode();
 175     }
 176 }