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 cpptooling.analyzer.clang.ast : Visitor; 15 import cpptooling.data : CppRoot, CppClass, CppMethod, CppCtor, CppDtor, 16 CFunction, CppNamespace, USRType, Language, LocationTag, Location; 17 18 import dextool.type : FileName; 19 20 import dextool.plugin.fuzzer.backend.interface_; 21 22 /// Data derived during analyze of one translation unit. 23 struct AnalyzeData { 24 static auto make() { 25 auto r = AnalyzeData(CppRoot.make); 26 return r; 27 } 28 29 CppRoot root; 30 alias root this; 31 32 /// Either all functions have the same or it is a mix which result in unknown. 33 Language languageOfTranslationUnit; 34 35 FileName fileOfTranslationUnit; 36 } 37 38 private enum LanguageAnalyzeState { 39 none, 40 unknown, 41 oneLanguage, 42 mixed 43 } 44 45 private LanguageAnalyzeState mergeLanguage(LanguageAnalyzeState st, 46 Language func_lang, ref Language current_lang) @safe pure nothrow @nogc { 47 import std.algorithm : among; 48 49 final switch (st) { 50 case LanguageAnalyzeState.none: 51 if (func_lang.among(Language.c, Language.cpp)) { 52 st = LanguageAnalyzeState.oneLanguage; 53 } else { 54 st = LanguageAnalyzeState.unknown; 55 } 56 break; 57 case LanguageAnalyzeState.unknown: 58 break; 59 case LanguageAnalyzeState.oneLanguage: 60 if (func_lang != current_lang) { 61 st = LanguageAnalyzeState.mixed; 62 } 63 break; 64 case LanguageAnalyzeState.mixed: 65 break; 66 } 67 68 final switch (st) { 69 case LanguageAnalyzeState.none: 70 break; 71 case LanguageAnalyzeState.unknown: 72 current_lang = Language.unknown; 73 break; 74 case LanguageAnalyzeState.oneLanguage: 75 current_lang = func_lang; 76 break; 77 case LanguageAnalyzeState.mixed: 78 current_lang = Language.unknown; 79 break; 80 } 81 82 return st; 83 } 84 85 final class TUVisitor : Visitor { 86 import std.typecons : scoped, NullableRef; 87 88 import cpptooling.analyzer.clang.ast : UnexposedDecl, FunctionDecl, 89 TranslationUnit, generateIndentIncrDecr, LinkageSpec; 90 import cpptooling.analyzer.clang.analyze_helper : analyzeFunctionDecl; 91 import cpptooling.data : CxReturnType; 92 import cpptooling.data.symbol : Container; 93 import cpptooling.analyzer.clang.cursor_logger : logNode, mixinNodeLog; 94 95 alias visit = Visitor.visit; 96 97 mixin generateIndentIncrDecr; 98 99 NullableRef!Container container; 100 AnalyzeData root; 101 102 private LanguageAnalyzeState lang_analyze_st; 103 104 this(NullableRef!Container container) { 105 this.container = container; 106 this.root = AnalyzeData.make; 107 } 108 109 override void visit(const(UnexposedDecl) v) { 110 mixin(mixinNodeLog!()); 111 v.accept(this); 112 } 113 114 override void visit(const(LinkageSpec) v) { 115 mixin(mixinNodeLog!()); 116 // extern "C"... etc 117 v.accept(this); 118 } 119 120 override void visit(const(FunctionDecl) v) { 121 mixin(mixinNodeLog!()); 122 123 auto result = analyzeFunctionDecl(v, container, indent); 124 if (!result.isValid) { 125 return; 126 } 127 128 auto func = CFunction(result.type.kind.usr, result.name, result.params, 129 CxReturnType(result.returnType), result.isVariadic, result.storageClass); 130 func.language = result.language; 131 root.put(func); 132 133 mergeLanguage(lang_analyze_st, result.language, root.languageOfTranslationUnit); 134 135 debug logger.tracef("FunctionDecl, language: %s tu(%s)", 136 result.language, root.languageOfTranslationUnit); 137 } 138 139 override void visit(const(TranslationUnit) v) { 140 mixin(mixinNodeLog!()); 141 142 root.fileOfTranslationUnit = FileName(v.cursor.spelling); 143 144 v.accept(this); 145 } 146 }