1 /** 2 Copyright: Copyright (c) 2017, Joakim Brännström. All rights reserved. 3 License: MPL-2 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 6 This Source Code Form is subject to the terms of the Mozilla Public License, 7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain 8 one at http://mozilla.org/MPL/2.0/. 9 */ 10 module dextool.plugin.fuzzer.backend.analyzer; 11 12 import logger = std.experimental.logger; 13 14 import libclang_ast.ast : Visitor; 15 import cpptooling.data : CppRoot, CppClass, CppMethod, CppCtor, CppDtor, 16 CFunction, CppNamespace, USRType, Language, LocationTag, Location; 17 18 import dextool.type : Path; 19 20 import dextool.plugin.fuzzer.backend.interface_; 21 22 /// Data derived during analyze of one translation unit. 23 struct AnalyzeData { 24 CppRoot root; 25 alias root this; 26 27 /// Either all functions have the same or it is a mix which result in unknown. 28 Language languageOfTranslationUnit; 29 30 Path fileOfTranslationUnit; 31 } 32 33 private enum LanguageAnalyzeState { 34 none, 35 unknown, 36 oneLanguage, 37 mixed 38 } 39 40 private LanguageAnalyzeState mergeLanguage(LanguageAnalyzeState st, 41 Language func_lang, ref Language current_lang) @safe pure nothrow @nogc { 42 import std.algorithm : among; 43 44 final switch (st) { 45 case LanguageAnalyzeState.none: 46 if (func_lang.among(Language.c, Language.cpp)) { 47 st = LanguageAnalyzeState.oneLanguage; 48 } else { 49 st = LanguageAnalyzeState.unknown; 50 } 51 break; 52 case LanguageAnalyzeState.unknown: 53 break; 54 case LanguageAnalyzeState.oneLanguage: 55 if (func_lang != current_lang) { 56 st = LanguageAnalyzeState.mixed; 57 } 58 break; 59 case LanguageAnalyzeState.mixed: 60 break; 61 } 62 63 final switch (st) { 64 case LanguageAnalyzeState.none: 65 break; 66 case LanguageAnalyzeState.unknown: 67 current_lang = Language.unknown; 68 break; 69 case LanguageAnalyzeState.oneLanguage: 70 current_lang = func_lang; 71 break; 72 case LanguageAnalyzeState.mixed: 73 current_lang = Language.unknown; 74 break; 75 } 76 77 return st; 78 } 79 80 final class TUVisitor : Visitor { 81 import std.typecons : scoped, NullableRef; 82 83 import libclang_ast.ast : UnexposedDecl, FunctionDecl, TranslationUnit, 84 generateIndentIncrDecr, LinkageSpec; 85 import cpptooling.analyzer.clang.analyze_helper : analyzeFunctionDecl; 86 import cpptooling.data : CxReturnType; 87 import cpptooling.data.symbol : Container; 88 import libclang_ast.cursor_logger : logNode, mixinNodeLog; 89 90 alias visit = Visitor.visit; 91 92 mixin generateIndentIncrDecr; 93 94 NullableRef!Container container; 95 AnalyzeData root; 96 97 private LanguageAnalyzeState lang_analyze_st; 98 99 this(NullableRef!Container container) { 100 this.container = container; 101 } 102 103 override void visit(scope const UnexposedDecl v) { 104 mixin(mixinNodeLog!()); 105 v.accept(this); 106 } 107 108 override void visit(scope const LinkageSpec v) { 109 mixin(mixinNodeLog!()); 110 // extern "C"... etc 111 v.accept(this); 112 } 113 114 override void visit(scope const FunctionDecl v) { 115 mixin(mixinNodeLog!()); 116 117 auto result = analyzeFunctionDecl(v, container, indent); 118 if (!result.isValid) { 119 return; 120 } 121 122 auto func = CFunction(result.type.kind.usr, result.name, result.params, 123 CxReturnType(result.returnType), result.isVariadic, result.storageClass); 124 func.language = result.language; 125 root.put(func); 126 127 mergeLanguage(lang_analyze_st, result.language, root.languageOfTranslationUnit); 128 129 debug logger.tracef("FunctionDecl, language: %s tu(%s)", 130 result.language, root.languageOfTranslationUnit); 131 } 132 133 override void visit(scope const TranslationUnit v) { 134 mixin(mixinNodeLog!()); 135 136 root.fileOfTranslationUnit = Path(v.cursor.spelling); 137 138 v.accept(this); 139 } 140 }