1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <idlc.hxx>
21 #include <errorhandler.hxx>
22 #include <astscope.hxx>
23 #include <astmodule.hxx>
24 #include <astservice.hxx>
25 #include <astconstants.hxx>
26 #include <astexception.hxx>
27 #include <astenum.hxx>
28 #include <astinterface.hxx>
29 #include <astoperation.hxx>
30 #include <astbasetype.hxx>
31 #include <astdeclaration.hxx>
32 #include <astparameter.hxx>
33 #include <astsequence.hxx>
34 #include <asttype.hxx>
35 #include <asttypedef.hxx>
36 
37 #include <osl/diagnose.h>
38 #include <osl/file.hxx>
39 #include <osl/thread.h>
40 
41 #include <algorithm>
42 
scopeAsDecl(AstScope * pScope)43 AstDeclaration* scopeAsDecl(AstScope* pScope)
44 {
45     if (pScope == nullptr) return nullptr;
46 
47     switch( pScope->getScopeNodeType() )
48     {
49         case NT_service:
50         case NT_singleton:
51             return static_cast<AstService*>(pScope);
52         case NT_module:
53         case NT_root:
54             return static_cast<AstModule*>(pScope);
55         case NT_constants:
56             return static_cast<AstConstants*>(pScope);
57         case NT_interface:
58             return static_cast<AstInterface*>(pScope);
59         case NT_operation:
60             return static_cast<AstOperation*>(pScope);
61         case NT_exception:
62             return static_cast<AstException*>(pScope);
63         case NT_struct:
64             return static_cast<AstStruct*>(pScope);
65         case NT_enum:
66             return static_cast<AstEnum*>(pScope);
67         default:
68             return nullptr;
69     }
70 }
71 
declAsScope(AstDeclaration * pDecl)72 AstScope* declAsScope(AstDeclaration* pDecl)
73 {
74     if (pDecl == nullptr) return nullptr;
75 
76     switch(pDecl->getNodeType())
77     {
78         case NT_interface:
79             return static_cast<AstInterface*>(pDecl);
80         case NT_service:
81         case NT_singleton:
82             return static_cast<AstService*>(pDecl);
83         case NT_module:
84         case NT_root:
85             return static_cast<AstModule*>(pDecl);
86         case NT_constants:
87             return static_cast<AstConstants*>(pDecl);
88         case NT_exception:
89             return static_cast<AstException*>(pDecl);
90         case NT_struct:
91             return static_cast<AstStruct*>(pDecl);
92         case NT_enum:
93             return static_cast<AstEnum*>(pDecl);
94         case NT_operation:
95             return static_cast<AstOperation*>(pDecl);
96         default:
97             return nullptr;
98    }
99 }
100 
predefineXInterface(AstModule * pRoot)101 static void predefineXInterface(AstModule* pRoot)
102 {
103     // define the modules  com::sun::star::uno
104     AstModule* pParentScope = pRoot;
105     AstModule* pModule = new AstModule("com", pParentScope);
106     pModule->setPredefined(true);
107     pParentScope->addDeclaration(pModule);
108     pParentScope = pModule;
109     pModule = new AstModule("sun", pParentScope);
110     pModule->setPredefined(true);
111     pParentScope->addDeclaration(pModule);
112     pParentScope = pModule;
113     pModule = new AstModule("star", pParentScope);
114     pModule->setPredefined(true);
115     pParentScope->addDeclaration(pModule);
116     pParentScope = pModule;
117     pModule = new AstModule("uno", pParentScope);
118     pModule->setPredefined(true);
119     pParentScope->addDeclaration(pModule);
120     pParentScope = pModule;
121 
122     // define XInterface
123     AstInterface* pInterface = new AstInterface("XInterface", nullptr, pParentScope);
124     pInterface->setDefined();
125     pInterface->setPredefined(true);
126     pInterface->setPublished();
127     pParentScope->addDeclaration(pInterface);
128 
129     // define XInterface::queryInterface
130     AstOperation* pOp = new AstOperation(static_cast<AstType*>(pRoot->lookupPrimitiveType(ET_any)),
131                                          "queryInterface", pInterface);
132     AstParameter* pParam = new AstParameter(DIR_IN, false,
133                                             static_cast<AstType*>(pRoot->lookupPrimitiveType(ET_type)),
134                                             "aType", pOp);
135     pOp->addDeclaration(pParam);
136     pInterface->addMember(pOp);
137 
138     // define XInterface::acquire
139     pOp = new AstOperation(static_cast<AstType*>(pRoot->lookupPrimitiveType(ET_void)),
140                            "acquire", pInterface);
141     pInterface->addMember(pOp);
142 
143     // define XInterface::release
144     pOp = new AstOperation(static_cast<AstType*>(pRoot->lookupPrimitiveType(ET_void)),
145                            "release", pInterface);
146     pInterface->addMember(pOp);
147 }
148 
initializePredefinedTypes(AstModule * pRoot)149 static void initializePredefinedTypes(AstModule* pRoot)
150 {
151     if ( !pRoot )
152          return;
153 
154     AstBaseType* pPredefined = new AstBaseType(ET_long, "long", pRoot);
155     pRoot->addDeclaration(pPredefined);
156 
157     pPredefined = new AstBaseType(ET_ulong, "unsigned long", pRoot);
158     pRoot->addDeclaration(pPredefined);
159 
160     pPredefined = new AstBaseType(ET_hyper, "hyper", pRoot);
161     pRoot->addDeclaration(pPredefined);
162 
163     pPredefined = new AstBaseType(ET_uhyper, "unsigned hyper", pRoot);
164     pRoot->addDeclaration(pPredefined);
165 
166     pPredefined = new AstBaseType(ET_short, "short", pRoot);
167     pRoot->addDeclaration(pPredefined);
168 
169     pPredefined = new AstBaseType(ET_ushort, "unsigned short", pRoot);
170     pRoot->addDeclaration(pPredefined);
171 
172     pPredefined = new AstBaseType(ET_float, "float", pRoot);
173     pRoot->addDeclaration(pPredefined);
174 
175     pPredefined = new AstBaseType(ET_double, "double", pRoot);
176     pRoot->addDeclaration(pPredefined);
177 
178     pPredefined = new AstBaseType(ET_char, "char", pRoot);
179     pRoot->addDeclaration(pPredefined);
180 
181     pPredefined = new AstBaseType(ET_byte, "byte", pRoot);
182     pRoot->addDeclaration(pPredefined);
183 
184     pPredefined = new AstBaseType(ET_any, "any", pRoot);
185     pRoot->addDeclaration(pPredefined);
186 
187     pPredefined = new AstBaseType(ET_string, "string", pRoot);
188     pRoot->addDeclaration(pPredefined);
189 
190     pPredefined = new AstBaseType(ET_type, "type", pRoot);
191     pRoot->addDeclaration(pPredefined);
192 
193     pPredefined = new AstBaseType(ET_boolean, "boolean", pRoot);
194     pRoot->addDeclaration(pPredefined);
195 
196     pPredefined = new AstBaseType(ET_void, "void", pRoot);
197     pRoot->addDeclaration(pPredefined);
198 }
199 
Idlc(Options * pOptions)200 Idlc::Idlc(Options* pOptions)
201     : m_pOptions(pOptions)
202     , m_bIsDocValid(false)
203     , m_bIsInMainfile(true)
204     , m_published(false)
205     , m_errorCount(0)
206     , m_warningCount(0)
207     , m_lineNumber(0)
208     , m_offsetStart(0)
209     , m_offsetEnd(0)
210     , m_parseState(PS_NoState)
211 {
212     m_pScopes.reset( new AstStack() );
213     // init root object after construction
214     m_pRoot = nullptr;
215     m_bGenerateDoc = m_pOptions->isValid("-C");
216 }
217 
~Idlc()218 Idlc::~Idlc()
219 {
220 }
221 
init()222 void Idlc::init()
223 {
224     m_pRoot.reset(new AstModule(NT_root, OString(), nullptr));
225 
226     // push the root node on the stack
227     m_pScopes->push(m_pRoot.get());
228     initializePredefinedTypes(m_pRoot.get());
229     predefineXInterface(m_pRoot.get());
230 }
231 
reset()232 void Idlc::reset()
233 {
234     m_bIsDocValid = false;
235     m_bIsInMainfile = true;
236     m_published = false;
237 
238     m_errorCount = 0;
239     m_warningCount = 0;
240     m_lineNumber = 0;
241     m_parseState = PS_NoState;
242 
243     m_fileName.clear();
244     m_mainFileName.clear();
245     m_realFileName.clear();
246     m_documentation.clear();
247 
248     m_pScopes->clear();
249     m_pRoot.reset( new AstModule(NT_root, OString(), nullptr) );
250 
251     // push the root node on the stack
252     m_pScopes->push(m_pRoot.get());
253     initializePredefinedTypes(m_pRoot.get());
254 
255     m_includes.clear();
256 }
257 
processDocumentation()258 OUString Idlc::processDocumentation()
259 {
260     OUString doc;
261     if (m_bIsDocValid) {
262         OString raw(getDocumentation());
263         if (m_bGenerateDoc) {
264             doc = OStringToOUString(raw, RTL_TEXTENCODING_UTF8);
265         } else if (raw.indexOf("@deprecated") != -1) {
266             //TODO: this check is somewhat crude
267             doc = "@deprecated";
268         }
269     }
270     return doc;
271 }
272 
lcl_writeString(::osl::File & rFile,::osl::FileBase::RC & o_rRC,OString const & rString)273 static void lcl_writeString(::osl::File & rFile, ::osl::FileBase::RC & o_rRC,
274         OString const& rString)
275 {
276     if (::osl::FileBase::E_None == o_rRC) {
277         sal_uInt64 nWritten(0);
278         o_rRC = rFile.write(rString.getStr(), rString.getLength(), nWritten);
279         if (static_cast<sal_uInt64>(rString.getLength()) != nWritten) {
280             o_rRC = ::osl::FileBase::E_INVAL; //?
281         }
282     }
283 }
284 
285 namespace {
286 
287 struct WriteDep
288 {
289     ::osl::File& m_rFile;
290     ::osl::FileBase::RC & m_rRC;
WriteDep__anon649392350111::WriteDep291     explicit WriteDep(::osl::File & rFile, ::osl::FileBase::RC & rRC)
292         : m_rFile(rFile), m_rRC(rRC) { }
operator ()__anon649392350111::WriteDep293     void operator() (OString const& rEntry)
294     {
295         lcl_writeString(m_rFile, m_rRC, " \\\n ");
296         lcl_writeString(m_rFile, m_rRC, rEntry);
297     }
298 };
299 
300 // write a dummy target for one included file, so the incremental build does
301 // not break with "No rule to make target" if the included file is removed
302 struct WriteDummy
303 {
304     ::osl::File& m_rFile;
305     ::osl::FileBase::RC & m_rRC;
WriteDummy__anon649392350111::WriteDummy306     explicit WriteDummy(::osl::File & rFile, ::osl::FileBase::RC & rRC)
307         : m_rFile(rFile), m_rRC(rRC) { }
operator ()__anon649392350111::WriteDummy308     void operator() (OString const& rEntry)
309     {
310         lcl_writeString(m_rFile, m_rRC, rEntry);
311         lcl_writeString(m_rFile, m_rRC, ":\n\n");
312     }
313 };
314 
315 }
316 
317 bool
dumpDeps(std::string_view rDepFile,OString const & rTarget)318 Idlc::dumpDeps(std::string_view rDepFile, OString const& rTarget)
319 {
320     ::osl::File depFile(
321             OStringToOUString(rDepFile, osl_getThreadTextEncoding()));
322     ::osl::FileBase::RC rc =
323         depFile.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create);
324     if (::osl::FileBase::E_None != rc) {
325         return false;
326     }
327     lcl_writeString(depFile, rc, rTarget);
328     if (::osl::FileBase::E_None != rc) {
329         return false;
330     }
331     lcl_writeString(depFile, rc, " :");
332     if (::osl::FileBase::E_None != rc) {
333         return false;
334     }
335     m_includes.erase(getRealFileName()); // eeek, that is a temp file...
336     ::std::for_each(m_includes.begin(), m_includes.end(),
337             WriteDep(depFile, rc));
338     lcl_writeString(depFile, rc, "\n\n");
339     ::std::for_each(m_includes.begin(), m_includes.end(),
340             WriteDummy(depFile, rc));
341     if (::osl::FileBase::E_None != rc) {
342         return false;
343     }
344     rc = depFile.close();
345     return ::osl::FileBase::E_None == rc;
346 }
347 
348 static Idlc* pStaticIdlc = nullptr;
349 
idlc()350 Idlc* idlc()
351 {
352     return pStaticIdlc;
353 }
354 
setIdlc(Options * pOptions)355 Idlc* setIdlc(Options* pOptions)
356 {
357     delete pStaticIdlc;
358     pStaticIdlc = new Idlc(pOptions);
359     pStaticIdlc->init();
360     return pStaticIdlc;
361 }
362 
resolveTypedefs(AstDeclaration const * type)363 AstDeclaration const * resolveTypedefs(AstDeclaration const * type) {
364     if (type != nullptr) {
365         while (type->getNodeType() == NT_typedef) {
366             type = static_cast< AstTypeDef const * >(type)->getBaseType();
367         }
368     }
369     return type;
370 }
371 
deconstructAndResolveTypedefs(AstDeclaration const * type,sal_Int32 * rank)372 AstDeclaration const * deconstructAndResolveTypedefs(
373     AstDeclaration const * type, sal_Int32 * rank)
374 {
375     *rank = 0;
376     for (;;) {
377         if (type == nullptr) {
378             return nullptr;
379         }
380         switch (type->getNodeType()) {
381         case NT_typedef:
382             type = static_cast< AstTypeDef const * >(type)->getBaseType();
383             break;
384         case NT_sequence:
385             ++(*rank);
386             type = static_cast< AstSequence const * >(type)->getMemberType();
387             break;
388         default:
389             return type;
390         }
391     }
392 }
393 
resolveInterfaceTypedefs(AstType const * type)394 AstInterface const * resolveInterfaceTypedefs(AstType const * type) {
395     AstDeclaration const * decl = resolveTypedefs(type);
396     OSL_ASSERT(decl->getNodeType() == NT_interface);
397     return static_cast< AstInterface const * >(decl);
398 }
399 
400 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
401