1 #include "semantic/HierarchyChecker.h"
5 #include "ast/AstNode.h"
6 #include "ast/DeclContext.h"
7 #include "utils/Utils.h"
11 static bool isSameMethodSignature(ast::MethodDecl
const* method1,
12 ast::MethodDecl
const* method2) {
14 if(method1->parameters().size() != method2->parameters().size())
return false;
16 for(size_t i = 0; i < method1->parameters().size(); i++) {
17 if(*method1->parameters()[i]->type() != *method2->parameters()[i]->type()) {
26 ast::ClassDecl
const* sub) {
27 if(super == sub)
return true;
28 for(
auto superClass : inheritanceMap_[sub]) {
29 if(
auto directSuper = dyn_cast<ast::ClassDecl>(superClass)) {
30 if(isSuperClass(super, directSuper))
return true;
37 ast::
Decl const* sub) {
38 if(super == sub)
return true;
39 for(
auto superInterface : inheritanceMap_[sub]) {
40 if(isSuperInterface(super, superInterface))
return true;
46 ast::
Decl const* parent) {
47 for(
auto member : getInheritedMembers(parent)) {
48 bool isHidden =
false;
49 for(
auto memberInherited : memberInheritancesMap_[node]) {
50 if(memberInherited->name() == member->name()) {
54 if(!isHidden) memberInheritancesMap_[node].insert(member);
59 ast::
Decl const* node, std::pmr::set<ast::Decl
const*>& visited) {
62 std::pmr::vector<ast::MethodDecl
const*> inheritedMethods;
63 memberInheritancesMap_[node] = std::pmr::set<ast::TypedDecl
const*>{};
64 auto nodeAsClass = dyn_cast<ast::ClassDecl>(node);
66 for(
auto member : nodeAsClass->fields()) {
67 memberInheritancesMap_[node].insert(member);
71 for(
auto super : inheritanceMap_[node]) {
72 if(
auto superClass = dyn_cast<ast::ClassDecl>(super)) {
73 if(!visited.count(superClass)) {
74 checkMethodInheritanceHelper(superClass, visited);
75 }
else if(!isInheritedSet(superClass)) {
76 diag.ReportError(superClass->location())
77 <<
"Cycle is detected in the inheritance graph. "
78 << superClass->name();
81 for(
auto method : getInheritedMethods(superClass)) {
82 inheritedMethods.emplace_back(method);
84 setInheritedMembersHelper(node, superClass);
85 }
else if(
auto superInterface = dyn_cast<ast::InterfaceDecl>(super)) {
86 if(!visited.count(superInterface)) {
87 checkMethodInheritanceHelper(superInterface, visited);
88 }
else if(!isInheritedSet(superInterface)) {
89 diag.ReportError(superInterface->location())
90 <<
"Cycle is detected in the inheritance graph. "
91 << superInterface->name();
94 for(
auto method : getInheritedMethods(superInterface)) {
95 inheritedMethods.emplace_back(method);
97 }
else if(super !=
nullptr) {
101 if(
auto classDecl = dyn_cast<ast::ClassDecl>(node)) {
102 checkClassMethod(classDecl, inheritedMethods);
103 checkClassConstructors(classDecl);
104 if(diag.Verbose(2)) {
105 diag.ReportDebug(2) <<
"Class: " << classDecl->name() << std::endl;
106 diag.ReportDebug(2) <<
"Inherited fields: " << std::endl;
107 for(
auto member : memberInheritancesMap_[node]) {
108 diag.ReportDebug(2) <<
"\t" << member->name() << std::endl;
111 }
else if(
auto interfaceDecl = dyn_cast<ast::InterfaceDecl>(node)) {
112 checkInterfaceMethod(interfaceDecl, inheritedMethods);
117 std::pmr::set<ast::Decl
const*> visited;
118 for(
auto cu : lu_->compliationUnits()) {
119 auto body = cu->body();
122 if(
auto classDecl = dyn_cast<ast::ClassDecl>(body)) {
123 if(visited.count(classDecl))
continue;
124 checkMethodInheritanceHelper(classDecl, visited);
125 }
else if(
auto interfaceDecl = dyn_cast<ast::InterfaceDecl>(body)) {
126 if(visited.count(interfaceDecl))
continue;
127 checkMethodInheritanceHelper(interfaceDecl, visited);
133 inheritanceMap_.clear();
134 for(
auto cu : lu_->compliationUnits()) {
135 auto body = cu->body();
139 if(
auto classDecl = dyn_cast<ast::ClassDecl>(body)) {
141 if(
auto superClass = classDecl->superClasses()[0]) {
142 auto superClassDecl = dyn_cast<ast::ClassDecl>(superClass->decl());
144 if(!superClassDecl) {
145 diag.ReportError(classDecl->location())
146 <<
"A class must not extend an interface. "
147 << classDecl->name();
151 if(superClassDecl->modifiers().isFinal()) {
152 diag.ReportError(classDecl->location())
153 <<
"A class must not extend a final class"
154 << classDecl->name();
156 inheritanceMap_[classDecl].insert(superClassDecl);
157 }
else if(
auto objectClass = classDecl->superClasses()[1]) {
159 inheritanceMap_[classDecl].insert(
160 cast<ast::ClassDecl>(objectClass->decl()));
164 for(
auto interface : classDecl->interfaces()) {
166 for(
auto other : classDecl->interfaces()) {
167 if(interface == other)
continue;
168 if(interface->decl() == other->decl()) {
169 diag.ReportError(classDecl->location())
170 <<
"A class must not implement the same interface twice. "
171 << classDecl->name();
176 auto interfaceDecl = dyn_cast<ast::InterfaceDecl>(interface->decl());
178 diag.ReportError(classDecl->location())
179 <<
"A class must not implement a class" << classDecl->name();
181 inheritanceMap_[classDecl].insert(interfaceDecl);
184 }
else if(
auto interfaceDecl = dyn_cast<ast::InterfaceDecl>(body)) {
186 for(
auto extends : interfaceDecl->extends()) {
187 for(
auto other : interfaceDecl->extends()) {
188 if(extends == other)
continue;
189 if(extends->decl() == other->decl()) {
190 diag.ReportError(interfaceDecl->location())
191 <<
"A interface must not extend the same interface twice. "
192 << interfaceDecl->name();
196 auto superInterface = dyn_cast<ast::InterfaceDecl>(extends->decl());
197 if(!superInterface) {
198 diag.ReportError(superInterface->location())
199 <<
"A interface must not extend a class"
200 << superInterface->name();
202 inheritanceMap_[interfaceDecl].insert(superInterface);
205 if(diag.Verbose(2)) {
207 <<
"Interface: " << interfaceDecl->name() <<
" extends "
208 << superInterface->name() <<
"\n";
213 checkMethodInheritance();
217 ast::ClassDecl
const* classDecl,
218 std::pmr::vector<ast::MethodDecl
const*>& inheritedMethods) {
219 std::pmr::vector<ast::MethodDecl
const*> allMethods;
220 std::pmr::vector<ast::MethodDecl
const*> inheritedNotOverriden;
222 for(
auto method : classDecl->methods()) {
223 allMethods.emplace_back(method);
224 for(
auto other : classDecl->methods()) {
225 if(method == other)
continue;
226 if(isSameMethodSignature(method, other)) {
227 diag.ReportError(method->location())
228 <<
"A class must not declare two methods with the same "
236 for(
auto method : classDecl->methods()) {
237 if(method->modifiers().isAbstract() &&
238 !classDecl->modifiers().isAbstract()) {
239 diag.ReportError(classDecl->location())
240 <<
"A class that contains (declares or inherits) any "
241 "abstract methods must be abstract. "
242 << classDecl->name();
248 for(
auto const* other : inheritedMethods) {
249 bool isOverriden =
false;
250 for(
auto const* method : classDecl->methods()) {
251 if(!isSameMethodSignature(method, other))
continue;
253 if(method->returnTy() != other->returnTy()) {
254 diag.ReportError(classDecl->location())
255 <<
"A method must not replace a method with a "
256 "different return type. "
259 if(!method->modifiers().isStatic() && other->modifiers().isStatic()) {
260 diag.ReportError(classDecl->location())
261 <<
"A nonstatic method must not replace a static "
265 if(method->modifiers().isStatic() && !other->modifiers().isStatic()) {
266 diag.ReportError(classDecl->location())
267 <<
"A static method must not replace a nonstatic "
271 if(method->modifiers().isProtected() && other->modifiers().isPublic()) {
272 diag.ReportError(classDecl->location())
273 <<
"A protected method must not replace a public "
277 if(other->modifiers().isFinal()) {
278 diag.ReportError(classDecl->location())
279 <<
"A method must not replace a final method. " << other->name();
282 if(!isOverriden) inheritedNotOverriden.emplace_back(other);
286 for(
auto method : inheritedNotOverriden) {
287 bool isImplemented = !method->modifiers().isAbstract();
288 for(
auto other : inheritedNotOverriden) {
289 if(isSameMethodSignature(method, other)) {
290 if(method->returnTy() != other->returnTy()) {
291 diag.ReportError(other->location())
292 <<
"A method must not replace a method with a "
293 "different return type. "
295 }
else if(!other->modifiers().isAbstract()) {
296 if(other->modifiers().isProtected() &&
297 method->modifiers().isPublic()) {
298 diag.ReportError(other->location())
299 <<
"A protected method must not replace a public "
303 isImplemented =
true;
307 if(!isImplemented && !classDecl->modifiers().isAbstract()) {
308 diag.ReportError(classDecl->location())
309 <<
"an abstract method must be implemented in a "
310 "non-abstract class "
312 << classDecl->location()
313 <<
"does not implement " << method->name()
314 << cast<ast::Decl>(method->parent())->location()
315 <<
"method is inherited from here"
316 << method->location()
317 <<
"abstract method is declared here";
318 }
else if(isImplemented == !method->modifiers().isAbstract()) {
319 allMethods.emplace_back(method);
323 setInheritedMethods(classDecl, allMethods);
326 if(diag.Verbose(2)) {
327 diag.ReportDebug(2) <<
"Class: " << classDecl
->name();
328 diag.ReportDebug(2) <<
"Inherited methods: ";
329 for(
auto method : allMethods) {
330 if (
auto parent = dyn_cast<ast::ClassDecl>(method->parent())) {
331 diag.ReportDebug(2) <<
"\t" << method->name() <<
" -> " << parent->name();
332 }
else if (
auto parent = dyn_cast<ast::InterfaceDecl>(method->parent())) {
333 diag.ReportDebug(2) <<
"\t" << method->name() <<
" -> " << parent->name();
339 void HierarchyChecker::checkClassConstructors(ast::ClassDecl
const* classDecl) {
340 for(
auto constructor : classDecl->constructors()) {
341 for(
auto other : classDecl->constructors()) {
342 if(constructor == other)
continue;
343 if(isSameMethodSignature(constructor, other)) {
344 diag.ReportError(constructor->location())
345 <<
"A class must not declare two constructors with the same "
347 << classDecl->name();
354 ast::InterfaceDecl
const* interfaceDecl,
355 std::pmr::vector<ast::MethodDecl
const*>& inheritedMethods) {
356 std::pmr::vector<ast::MethodDecl
const*> allMethods;
358 for(
auto method : interfaceDecl->methods()) {
359 allMethods.emplace_back(method);
360 for(
auto other : interfaceDecl->methods()) {
361 if(method == other)
continue;
362 if(isSameMethodSignature(method, other)) {
363 diag.ReportError(method->location())
364 <<
"An interface must not declare two methods with the same "
373 cast<ast::ClassDecl>(interfaceDecl->objectSuperclass()->decl());
374 for(
auto method : interfaceDecl->methods()) {
375 for(
auto other : objectClass->methods()) {
376 if(!isSameMethodSignature(method, other))
continue;
377 if(method->returnTy() != other->returnTy()) {
378 diag.ReportError(interfaceDecl->location())
379 <<
"A method must not replace a method with a "
380 "different return type. "
383 if(method->modifiers().isProtected() && other->modifiers().isPublic()) {
384 diag.ReportError(interfaceDecl->location())
385 <<
"A protected method must not replace a public "
389 if(other->modifiers().isFinal()) {
390 diag.ReportError(interfaceDecl->location())
391 <<
"A method must not replace a final method. " << other->name();
396 for(
auto method : inheritedMethods) {
397 bool isOverriden =
false;
398 for(
auto other : interfaceDecl->methods()) {
399 if(isSameMethodSignature(method, other)) {
400 if(method->returnTy() != other->returnTy()) {
401 diag.ReportError(method->location())
402 <<
"An interface must not contain two methods with the same "
410 if(!isOverriden) allMethods.emplace_back(method);
413 for(
auto method : allMethods) {
414 for(
auto other : allMethods) {
415 if(method == other)
continue;
416 if(isSameMethodSignature(method, other) &&
417 method->returnTy() != other->returnTy()) {
418 diag.ReportError(method->location())
419 <<
"An interface must not contain two methods with the same "
427 setInheritedMethods(interfaceDecl, allMethods);
430 if(diag.Verbose(2)) {
431 diag.ReportDebug(2) <<
"Interface: " << interfaceDecl
->name();
432 diag.ReportDebug(2) <<
"Inherited methods:";
433 for(
auto method : allMethods) diag.ReportDebug(2) <<
"\t" << method->name();